/** @jsxImportSource react */

import _ from 'lodash';
import { useEffect, useMemo, useState } from 'react';
import { Button } from '~/components/react/shadcn/ui/button';
import { Input } from '~/components/react/shadcn/ui/input';
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '~/components/react/shadcn/ui/dialog';
import type { Result, SimpleTag } from '~/common/types';
import { distinctUntilChanged, debounceTime } from 'rxjs/operators';

import AddTagsButton from './AddTagsButton';
import Tag from './Tag';
import { BehaviorSubject } from 'rxjs';
import { Loader } from 'lucide-react';
import AlertMessage from '~/components/react/ui/AlertMessage';

type SearchResultProps = {
  result: Result<SimpleTag[], string>;
  showCreateTag: boolean;
  onSearchedTagSelect: (tag: SimpleTag) => void;
  onCreateTagClick: () => void;
};

function SearchResult({ result, showCreateTag, onSearchedTagSelect, onCreateTagClick }: SearchResultProps) {
  if (result.ok) {
    const searchedTags = result.data;
    return (
      <div>
        {searchedTags.length === 0
          ? showCreateTag && (
              <p>
                没有找到相关标签。
                <span className="underline cursor-pointer" onClick={() => onCreateTagClick()}>
                  戳此创建标签
                </span>
              </p>
            )
          : searchedTags.map((tag) => (
              <Tag selected={false} key={tag.id.toString()} tag={tag} onClick={onSearchedTagSelect} />
            ))}
      </div>
    );
  } else {
    return <AlertMessage title="搜索标签失败" description={result.error} />;
  }
}

function CreateTagError({ error }: { error: string }) {
  return error ? <AlertMessage title="创建标签失败" description={error} /> : null;
}

type AddTagsModalProps = {
  onSearchTags: (text: string) => Promise<Result<SimpleTag[], string>>;
  onCreateTag: (text: string) => Promise<Result<SimpleTag, string>>;
  value: SimpleTag[];
  onChange: (tags: SimpleTag[]) => void;
};

export default function TagsInput({ onSearchTags, onCreateTag, value, onChange }: AddTagsModalProps) {
  const [text, setText] = useState('');
  const [searchResult, setSearchResult] = useState<Result<SimpleTag[], string>>({ ok: true, data: [] });
  const [createTagError, setCreateTagError] = useState<string>('');
  const [searching, setSearching] = useState(false);
  const searchedTagsSubject = useMemo(() => new BehaviorSubject<string>(text), []);

  useEffect(() => {
    searchedTagsSubject.next(text);
    setCreateTagError('');
  }, [text]);

  useEffect(() => {
    const subscription = searchedTagsSubject
      .pipe(
        distinctUntilChanged(), // deplicate
        debounceTime(300) // delay
      )
      .subscribe((it) => {
        if (_.isEmpty(it)) {
          setSearching(false);
          return;
        }

        onSearchTags(it)
          .then((res) => {
            setSearching(false);
            setSearchResult(res);
          })
          .catch((err) => {
            setSearching(false);
            setSearchResult({ ok: false, error: '' + err.message });
          });
      });
    return () => subscription.unsubscribe();
  }, []);

  return (
    <Dialog>
      <DialogTrigger>
        <AddTagsButton />
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>添加标签</DialogTitle>
        </DialogHeader>
        <div className="grid gap-4 py-4">
          <div>
            已选择标签：
            <div className="flex flex-wrap gap-1 mt-3">
              {value.map((tag) => (
                <Tag
                  selected
                  key={tag.id.toString()}
                  tag={tag}
                  onClick={(t) => {
                    onChange(_.filter(value, (it) => it.id !== t.id));
                  }}
                />
              ))}
            </div>
          </div>
          <Input
            value={text}
            placeholder="搜索标签"
            onChange={(e) => {
              setSearching(true);
              setText(e.target.value);
            }}
          />
        </div>
        <div>
          {searching ? (
            <p className="flex items-center gap-1">
              <Loader className="animate-spin" /> <i>搜索中...</i>
            </p>
          ) : (
            <div>
              <SearchResult
                result={searchResult}
                showCreateTag={!_.isEmpty(text)}
                onSearchedTagSelect={(t) => {
                  onChange(_.uniqBy([...value, t], 'id'));
                }}
                onCreateTagClick={() => {
                  onCreateTag(text)
                    .then((res) => {
                      if (res.ok) {
                        onChange([...value, res.data]);
                        setText('');
                        setSearchResult({ ok: true, data: [] });
                      } else {
                        setCreateTagError(res.error);
                      }
                    })
                    .catch((err) => {
                      setCreateTagError('' + err.message);
                    });
                }}
              />
              <CreateTagError error={createTagError} />
            </div>
          )}
        </div>
        <DialogFooter>
          <DialogClose asChild>
            <Button>完成</Button>
          </DialogClose>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
